﻿using Dyao.Book.Application.Abstractions;
using Dyao.Book.Contract;
using Microsoft.Extensions.DependencyInjection;

namespace Dyao.Book.Application
{

    public static class TaskCenterContextExtensions
    {
        public static ITaskCenterParameters GetParameters(this ITaskCenterContext context)
        {
            return GetParametersManger(context).GetParameters();
        }

        /// <summary>
        /// 获取参数字典
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="context"></param>
        /// <returns></returns>
        public static ITaskCenterParameters<T> GetParameters<T>(this ITaskCenterContext context)
            where T : class
        {
            return GetParametersManger(context).GetParameters<T>();
        }

        /// <summary>
        /// 将请求参数反序列为 <typeparamref name="T"/> 对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="context"></param>
        /// <returns></returns>
        public static T DeserializeParametersTo<T>(this ITaskCenterContext context)
            where T : class
        {
            var p = GetParametersManger(context).GetParameters<T>();

            return p.Model;
        }

        /// <summary>
        /// 获取导入参数字典对象
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public static ITaskCenterParameters<TaskCenterImportRequestParamsDto> GetImportParameters(this ITaskCenterContext context)
        {
            return GetParametersManger(context).GetParameters<TaskCenterImportRequestParamsDto>();
        }

        /// <summary>
        /// 获取参数中导入文件的路径参数值
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public static string GetImportFilePathValue(this ITaskCenterContext context)
        {
            var filePath = GetParametersManger(context).GetParameters().GetValue<string>("importFilePath", nameof(TaskCenterImportRequestParamsDto.ImportFilePath));

            return filePath;
        }

        /// <summary>
        /// 获取导出参数字典对象
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public static ITaskCenterParameters<TaskCenterExportRequestParamsDto> GetExportParameters(this ITaskCenterContext context)
        {
            return GetParametersManger(context).GetParameters<TaskCenterExportRequestParamsDto>();
        }

        /// <summary>
        /// 从参数字典中获取名为 “queryFilter” 或“requestFilter”或者“requestParams”或者“filter”的参数值，反序列为 <typeparamref name="T"/> 对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="context"></param>
        /// <returns></returns>
        public static T GetQueryFilterModel<T>(this ITaskCenterContext context)
        {
            var p = GetParametersManger(context).GetParameters();

            var filter = p.GetFilterModel<T>();

            return filter;
        }

        /// <summary>
        /// 根据 <paramref name="keys"/> 获取参数值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="context"></param>
        /// <param name="keys"></param>
        /// <returns></returns>
        public static T GetParameterValue<T>(this ITaskCenterContext context, params string[] keys)
        {
            var p = GetParametersManger(context).GetParameters();

            var result = p.GetValue<T>(keys);

            return result;
        }

        private static Task<T> DeserializeRequestParameterAsync<T>(ITaskCenterContext context)
        {
            var serializer = context.ServiceProvider.GetService<ITaskCenterParametersSerializerFactory>().Create(context.TaskModel);

            if (serializer is ITaskCenterRequestParamsSerializerSetter setter)
            {
                setter.SetParametersStringLoader((taskId) => context.GetRequestParametersStringAsync());
            }

            return serializer.DeserializeAsync<T>(context.TaskModel);
        }

        #region parameter manager

        private static string _taskcenterParametersMangerKey = "_parameters.Manger";

        /// <summary>
        /// 获取参数对象管理器
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        private static ParametersManger GetParametersManger(ITaskCenterContext context)
        {
            if (!context.TryGetValue(_taskcenterParametersMangerKey, out ParametersManger manger))
            {
                manger = new ParametersManger(context);
                context.Set(_taskcenterParametersMangerKey, manger);
            }

            return manger;
        }

        private class ParametersManger
        {
            private readonly ITaskCenterContext _context;
            private List<ITaskCenterParameters> _list;

            public ParametersManger(ITaskCenterContext context)
            {
                this._context = context;
            }

            public IList<ITaskCenterParameters> List => _list ??= new List<ITaskCenterParameters>();

            public ITaskCenterParameters GetParameters()
            {
                var list = this.List;

                var item = list.FirstOrDefault();

                if (item == null)
                {
                    item = DeserializeRequestParameterAsync<ITaskCenterParameters>(_context).GetAwaiter().GetResult();
                    list.Add(item);
                }

                return item;
            }

            public ITaskCenterParameters<T> GetParameters<T>()
                where T : class
            {
                var list = this.List;

                if (list.Count > 0)
                {
                    foreach (var item in list)
                    {
                        if (item is ITaskCenterParameters<T> p) return p;
                    }

                    var first = list.FirstOrDefault(a => a is DefaultTaskCenterParameters) as DefaultTaskCenterParameters;

                    ITaskCenterParameters<T> result = null;
                    if (first != null) result = new DefaultTaskCenterParameters<T>(first);
                    else result = new DefaultTaskCenterParameters<T>(list.First());

                    list.Add(result);

                    return result;
                }

                var parameters = DeserializeRequestParameterAsync<ITaskCenterParameters<T>>(_context).GetAwaiter().GetResult();
                list.Add(parameters);

                return parameters;
            }
        }

        #endregion parameter manager
    }
}
